package com.apes.fn.scm.retailOrder.service;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.scm.retailOrder.model.*;
import com.apes.fn.scm.retailOrder.repository.RetailOrderDiscountItemRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderExtensionRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.product.repository.ServeCategoryRepository;
import com.apes.scm.voucher.model.VoucherExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.Param;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.*;

/**
 * 零售单扩展类服务
 *
 * @author wuq
 * @Time 2022-5-19 19:05
 * @Description
 */
@Service("retailOrderExtensionService")
public class RetailOrderExtensionService extends DomainService {

    @Autowired
    private RetailOrderRepository retailOrderRepository;
    @Autowired
    private RetailOrderExtensionRepository retailOrderExtensionRepository;
    @Autowired
    private ServeCategoryRepository serveCategoryRepository;
    @Autowired
    private RetailOrderDiscountItemRepository retailOrderDiscountItemRepository;

    public void saveByEsb(SimpleRequest request) {
        String id = request.get("id");
        RetailOrder retailOrder = retailOrderRepository.findOne(id);
        save(retailOrder);
    }

    @OutboxSubscriber(id = "retailOrder.extension.save", name = "保存零售单扩展表")
    public void saveByOutBox(OutboxPayloadWrapper wrapper) {
        JSONObject param = JSONObject.parseObject(wrapper.getPayload());
        String id = param.getString("id");
        RetailOrder retailOrder = retailOrderRepository.findOne(id);
        save(retailOrder);
    }

    private void save(RetailOrder retailOrder) {

        retailOrder.getSaleItems().forEach( retailOrderItem -> {
            List<RetailOrderExtension> items = retailOrderExtensionRepository.findAll(JpaDsl.toCriteriaByEq("retailOrderItemId", retailOrderItem.getId()));
            if (!items.isEmpty()) return;  // 写入过的数据就不在写入

            RetailOrderExtension retailOrderExtension = new RetailOrderExtension();
            retailOrderExtension.setRetailOrderId(retailOrder.getId());
            retailOrderExtension.setRetailOrderItemId(retailOrderItem.getId());

            // 添加公司信息
            addCompanyAndDeptInfo(retailOrderExtension, retailOrder);

            // 添加商品信息
            addProductInfo(retailOrderExtension, retailOrderItem);

            // 添加客户信息
            addCustomerInfo(retailOrderExtension, retailOrder);

            // 金额汇总
            amount(retailOrderExtension, retailOrderItem);
            retailOrderExtensionRepository.saveAndFlush(retailOrderExtension);
        });
    }

    private void addCompanyAndDeptInfo(RetailOrderExtension retailOrderExtension, RetailOrder retailOrder){
        retailOrderExtension.setCompanyName(retailOrder.getCompany().getName());
        retailOrderExtension.setDeptName(retailOrder.getDept().getName());
        Optional.ofNullable(retailOrder.getServiceDept()).ifPresent(clerk -> retailOrderExtension.setServiceDeptName(retailOrder.getServiceDept().getName()));
        Optional.ofNullable(retailOrder.getMakeInvoice()).ifPresent(clerk -> retailOrderExtension.setMakeInvoiceName(retailOrder.getMakeInvoice().getName()));

        // 运营模式
        retailOrderExtension.setOperation(retailOrder.getCompany().getParty().getCorporate().getOperation().getId());
        retailOrderExtension.setOperationName(retailOrder.getCompany().getParty().getCorporate().getOperation().getDescription());
    }

    private void addProductInfo(RetailOrderExtension retailOrderExtension, RetailOrderItem retailOrderItem) {
        retailOrderExtension.setProductState(retailOrderItem.getProduct().getState());
        retailOrderExtension.setProductName(retailOrderItem.getProduct().getName());

        retailOrderExtension.setTaxName(retailOrderItem.getTax().getName());
        retailOrderExtension.setUomName(retailOrderItem.getUom().getName());

        retailOrderExtension.setProductClassifyId(retailOrderItem.getProduct().getClassify().getId());
        retailOrderExtension.setProductClassify(retailOrderItem.getProduct().getClassify().getName());

        retailOrderExtension.setBrandId(retailOrderItem.getProduct().getBrand().getId());
        retailOrderExtension.setBrandName(retailOrderItem.getProduct().getBrand().getName());

        retailOrderExtension.setProductGroupId(retailOrderItem.getProduct().getProductGroup().getId());
        retailOrderExtension.setProductGroupName(retailOrderItem.getProduct().getProductGroup().getName());

        Optional.ofNullable(retailOrderItem.getProduct().getCategory())
                .ifPresent(category -> {
                    retailOrderExtension.setCategoryId(category.getId());
                    retailOrderExtension.setCategoryName(category.getName());
                });

        serveCategoryRepository.findAll(JpaDsl.toCriteriaByEq("classify.id", retailOrderItem.getProduct().getClassify().getId()))
                .stream().findFirst().ifPresent(
                        serveCategory -> {
                            retailOrderExtension.setServeTypeId(serveCategory.getServeType().getId());
                            retailOrderExtension.setServeTypeName(serveCategory.getServeType().getName());
                        });

    }
    
    private void addCustomerInfo(RetailOrderExtension retailOrderExtension, RetailOrder retailOrder){
        if (retailOrder.getCustomerExpand() == null) return;

        retailOrderExtension.setCarLicense(retailOrder.getCustomerExpand().getCarLicense());
        retailOrderExtension.setRealname(retailOrder.getCustomerExpand().getRealname());
        retailOrderExtension.setMobile(retailOrder.getCustomerExpand().getMobile());
        retailOrderExtension.setUnitClientId(retailOrder.getCustomerExpand().getUnitClientId());
        retailOrderExtension.setUnitClientName(retailOrder.getCustomerExpand().getUnitClientName());
    }

    private void amount(RetailOrderExtension retailOrderExtension, RetailOrderItem retailOrderItem){
        // 折扣明细
        double discountAmount = retailOrderItem.getRetailDiscounts().stream().mapToDouble(RetailOrderDiscount::getDiscountAmount).sum();
        retailOrderExtension.setRetailDiscountAmount(discountAmount);

        // 年卡兑换券金额
        double couponDiscountAmount = retailOrderItem.getRetailDiscounts().stream().mapToDouble(RetailOrderDiscount::getCouponProfitAmount).sum();
        retailOrderExtension.setCouponDiscountAmount(couponDiscountAmount);

        // 异业合作金额
        double crossDiscountAmount = retailOrderItem.getRetailDiscounts().stream()
                .filter(retailOrderDiscount -> retailOrderDiscount.getDiscountType()!=null&&"001622".equals(retailOrderDiscount.getDiscountType().getId()))
                .mapToDouble(RetailOrderDiscount::getDiscountAmount)
                .sum();
        retailOrderExtension.setCrossDiscountAmount(crossDiscountAmount);

        // 收银台折扣金额
        double cashierDeskDiscountAmount = retailOrderItem.getRetailDiscounts().stream()
                .filter(retailOrderDiscount -> retailOrderDiscount.getDiscountType()!=null&&"001612".equals(retailOrderDiscount.getDiscountType().getId()))
                .mapToDouble(RetailOrderDiscount::getDiscountAmount)
                .sum();
        retailOrderExtension.setCashierDeskDiscountAmount(cashierDeskDiscountAmount);

        // 卡券优惠金额
        double ticketDiscountAmount = retailOrderItem.getRetailDiscounts().stream().mapToDouble(RetailOrderDiscount::getCouponDiscountAmount).sum();
        retailOrderExtension.setTicketDiscountAmount(ticketDiscountAmount);

        // 折扣红包金额 与 保呗红包金额
        retailOrderItem.getRetailDiscounts().stream()
                .filter(retailOrderDiscount -> "001598".equals(retailOrderDiscount.getDiscountType().getId()))
                .forEach( retailOrderDiscount -> {
                    // 保呗红包
                    double baobeiEnvelopeCash = retailOrderDiscount.getRetailDiscountItems().stream()
                            .filter(retailOrderDiscountItem -> "1".equals(retailOrderDiscountItem.getType()))
                            .mapToDouble(RetailOrderDiscountItem::getAmount).sum();
                    retailOrderExtension.setBaobeiEnvelopeCash(baobeiEnvelopeCash);

                    // 折扣红包金额
                    double redEnvelopeCash = retailOrderDiscount.getRetailDiscountItems().stream()
                            .filter(retailOrderDiscountItem -> "0".equals(retailOrderDiscountItem.getType()))
                            .mapToDouble(RetailOrderDiscountItem::getAmount).sum();
                    retailOrderExtension.setRedEnvelopeCash(redEnvelopeCash);
                });
    }


    @Autowired
    private TransactionTemplate transactionTemplate;

    public int execute(Callback callback) {
        return transactionTemplate.execute(status -> {
            try {
                return callback.execute();
            } catch (Exception e) {
                status.isRollbackOnly();
                throw e;
            }
        });
    }

    @FunctionalInterface
    public interface Callback {
        @Nullable
        int execute();
    }


    /**
     * 修改数据
     * @param request {"page":"0", "size":"30", "startDate":"2022-07-10", "endDate":"2022-08-10"}
     */
    public void collectData(SimpleRequest request) {
        JSONObject jsonObject = request.getJO();
        int page = jsonObject.getInteger("page");
        int size = jsonObject.getInteger("size");

        Date startDate = jsonObject.getDate("startDate");
        Date endDate = jsonObject.getDate("endDate");

        Sort sort = new Sort(Sort.Direction.ASC, "createDate");
        while (true) {
            Pageable pageable = PageRequest.of(page, size, sort);
            int execute = 0;
            try {
                execute = execute(() -> {
                    Page<Map<String, String>> maps = retailOrderDiscountItemRepository.findAllForUpdateDiscount(startDate, endDate, pageable);
                    maps.getContent().forEach(this::updateAmount);
                    return maps.getContent().size();
                });
            } catch (Exception e) {
                //即使异常也不处理，宁愿不汇扩展表也不要影响业务
            }
            page = page + 1;
            if (execute < size) {
                break;
            }
            System.out.println("============================== page: " + page);
        }
    }

    public void updateById(SimpleRequest request){
        String id = request.get("id");
        updateAmount(MapUtil.mapper("retailOrderId", id));
    }

    private void updateAmount(Map map){
        String retailOrderId = map.get("retailOrderId").toString();
        RetailOrder retailOrder = retailOrderRepository.findOne(retailOrderId);

        retailOrder.getSaleItems().forEach( retailOrderItem -> {
            List<RetailOrderExtension> retailOrderExtensions = retailOrderExtensionRepository.findAll(
                    JpaDsl.toCriteriaByEq("retailOrderId", retailOrderId, "retailOrderItemId", retailOrderItem.getId()));

            RetailOrderExtension retailOrderExtension = retailOrderExtensions.get(0);
            amount(retailOrderExtension, retailOrderItem);
            retailOrderExtensionRepository.saveAndFlush(retailOrderExtension);
        });
    }

}
